#include "ohos_external_audio_source_impl.h"
#include "rtc_base/logging.h"
#include "rtc_base/helpers.h"
#include "audio/utility/audio_frame_operations.h"
#include "audio/remix_resample.h"
#include <iterator>

namespace ohoswebrtc {

const std::vector<int32_t> kSupportFreqs = {48000, 44100, 16000, 32000, 8000};
// implements ExternalAudioSource
OHOSExternalAudioSourceImpl::OHOSExternalAudioSourceImpl()
  :sample_rate_(0),
  ssrc_((int)rtc::CreateRandomId()),
  insufficient_(true),
  low_level_(1),
  high_level_(4),
  max_level_(500),
  no_data_count_(0),
  frames_(0) {
  RTC_LOG(LS_INFO) << "ctor.";
}

OHOSExternalAudioSourceImpl::~OHOSExternalAudioSourceImpl() {
  RTC_LOG(LS_INFO) << "~dtor.";
}

int OHOSExternalAudioSourceImpl::DeliverFrame(unsigned char* pcm_data,
  unsigned int nSamples,
  unsigned int nBytesPerSample,
  unsigned int nChannels,
  unsigned int samplesPerSec,
  unsigned short rec_delay_ms) {

  auto result = std::find(kSupportFreqs.begin(), kSupportFreqs.end(), samplesPerSec);
  if (result == kSupportFreqs.end()) {
      return -1;
  }
  if (sample_rate_ != samplesPerSec) {
    Reset();
    sample_rate_ = samplesPerSec;
  }
  
  std::shared_ptr<webrtc::AudioFrame> audio_frame(new webrtc::AudioFrame());
  audio_frame->UpdateFrame(rec_delay_ms, (int16_t*)pcm_data, nSamples,
                          samplesPerSec,
                          webrtc::AudioFrame::SpeechType::kNormalSpeech,
                          webrtc::AudioFrame::kVadUnknown, nChannels);

  {
    webrtc::MutexLock lock(&mutex_);
    write_list_.push_back(audio_frame);
    if (write_list_.size() > max_level_) {
      RTC_LOG(LS_INFO) << "scale write";
      ScaleAudioFrameList(write_list_, high_level_);
    }
  }
  return 0;
}

// implments AudioMixer::Source interface
webrtc::AudioMixer::Source::AudioFrameInfo
OHOSExternalAudioSourceImpl::GetAudioFrameWithInfo(
  int sample_rate_hz,
  webrtc::AudioFrame* audio_frame) {
  frames_++;
  if (read_list_.size() < high_level_) {
    webrtc::MutexLock lock(&mutex_);
    read_list_.insert(read_list_.end(), write_list_.begin(), write_list_.end());
    write_list_.clear();
  }

  if (read_list_.size() > max_level_) {
    //save the last high_level_ frames;
    RTC_LOG(LS_INFO) << "scale read";
    ScaleAudioFrameList(read_list_, high_level_);
  }

  if (read_list_.size() < low_level_) {
    no_data_count_ ++;
    insufficient_ = true;
    return webrtc::AudioMixer::Source::AudioFrameInfo::kError;
  }
  if (insufficient_) {
    if (read_list_.size() < high_level_) {
      no_data_count_++;
      return webrtc::AudioMixer::Source::AudioFrameInfo::kError;
    } else {
      insufficient_ = false;
    }
  }
  
  if (frames_ > 1000) {
    if (no_data_count_ != 0) {
      RTC_LOG(LS_INFO) << "miss " << no_data_count_ << "in frames " << frames_;
    }
    frames_ = 0;
    no_data_count_ = 0;
  }
  std::shared_ptr<webrtc::AudioFrame> frame = read_list_.front();
  read_list_.pop_front();

  if (sample_rate_hz != frame->sample_rate_hz_) {
    audio_frame->samples_per_channel_ = sample_rate_hz / 100; //10ms
    audio_frame->sample_rate_hz_ = sample_rate_hz;
    audio_frame->num_channels_ = frame->num_channels_;
    webrtc::voe::RemixAndResample(*frame, &deliver_resampler_, audio_frame);
  } else {
    audio_frame->CopyFrom(*frame);
  }
  return webrtc::AudioMixer::Source::AudioFrameInfo::kNormal;
}


int OHOSExternalAudioSourceImpl::Ssrc() const {
  return ssrc_;
}

int OHOSExternalAudioSourceImpl::PreferredSampleRate() const {
  return sample_rate_;
}

void OHOSExternalAudioSourceImpl::ScaleAudioFrameList(std::list<std::shared_ptr<webrtc::AudioFrame>>& list, size_t scale) {
  RTC_DCHECK_GT(list.size(), scale);
  auto scale_begin = list.begin();
  auto scale_end = list.begin();
  std::advance(scale_end, list.size() - scale);
  list.erase(scale_begin, scale_end);
}

void OHOSExternalAudioSourceImpl::Reset() {
  RTC_LOG(LS_INFO) << "Reset";
  no_data_count_ = 0;
  frames_ = 0;
  insufficient_ = true;
  webrtc::MutexLock lock(&mutex_);
  read_list_.clear();
  write_list_.clear();
}

}

